From fd2081bdb2f0dd1fe40922bfc019dd341b44868d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Caol=C3=A1n=20McNamara?= Date: Fri, 12 Jun 2026 20:32:27 +0000 Subject: [PATCH] [PATCH] match the package content provider when checking a vnd.sun.star.pkg url MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit IsExoticProtocol used GetHost() to recover the nested package url of a vnd.sun.star.pkg url, but the package content provider in ucb/source/ucp/package/pkguri.cxx uses the whole authority between "://" and the next '/', which GetHost() truncates at '@'. Check the same substring the provider does. The vnd.sun.star.zip branch below already did the equivalent extraction, so pull the shared parts into a helper that both branches call. Signed-off-by: Caolán McNamara Change-Id: I27be6a839108f2e58d62baefc1a71dcbfc9a4568 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4410 Tested-by: Jenkins CPCI Reviewed-by: Stephan Bergmann (cherry picked from commit ce436efb34d2e0e90ee2cdb450da285530c562f7) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206681 Reviewed-by: Xisco Fauli Tested-by: Jenkins (cherry picked from commit 4ba5567cc44be760066c0c45c99949f790cf181a) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206701 Gbp-Pq: Name CVE-2026-63278.diff --- tools/qa/cppunit/test_urlobj.cxx | 5 +++++ tools/source/fsys/urlobj.cxx | 37 ++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/tools/qa/cppunit/test_urlobj.cxx b/tools/qa/cppunit/test_urlobj.cxx index 31347cf4b57..949b2ac155c 100644 --- a/tools/qa/cppunit/test_urlobj.cxx +++ b/tools/qa/cppunit/test_urlobj.cxx @@ -370,6 +370,11 @@ namespace tools_urlobj CPPUNIT_ASSERT_EQUAL(INetProtocol::VndSunStarPkg, url.GetProtocol()); CPPUNIT_ASSERT(!url.IsExoticProtocol()); } + { + INetURLObject url(u"vnd.sun.star.pkg://vnd.sun.star.expand%3Ahttp%3A%2F%2F127.0.0.1%2F%24%7BHOME%7D@example.com/x"); + CPPUNIT_ASSERT_EQUAL(INetProtocol::VndSunStarPkg, url.GetProtocol()); + CPPUNIT_ASSERT(url.IsExoticProtocol()); + } { INetURLObject url(u"vnd.sun.star.zip://slot%3A0"); CPPUNIT_ASSERT_EQUAL(INetProtocol::Generic, url.GetProtocol()); diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx index 7f6e43cfc32..91b33437c60 100644 --- a/tools/source/fsys/urlobj.cxx +++ b/tools/source/fsys/urlobj.cxx @@ -4887,6 +4887,25 @@ OUString INetURLObject::CutExtension() return OUString(); } +namespace { + +// Treat the substring of rURL from nStart up to the next '/' or '?' as a +// percent-encoded nested url and report whether that nested url is an +// exotic protocol. +bool isExoticNestedProtocol(const OUString& rURL, sal_Int32 nStart) +{ + auto const find = [&rURL, nStart](auto c) { + auto const n = rURL.indexOf(c, nStart); + return n == -1 ? rURL.getLength() : n; + }; + return INetURLObject( + INetURLObject::decode(rURL.subView(nStart, std::min(find('/'), find('?')) - nStart), + INetURLObject::DecodeMechanism::WithCharset)) + .IsExoticProtocol(); +} + +} + bool INetURLObject::IsExoticProtocol() const { if (m_eScheme == INetProtocol::Slot || @@ -4899,8 +4918,16 @@ bool INetURLObject::IsExoticProtocol() const return true; } if (m_eScheme == INetProtocol::VndSunStarPkg) { - return INetURLObject(GetHost(INetURLObject::DecodeMechanism::WithCharset)) - .IsExoticProtocol(); + // The package content provider (ucb/source/ucp/package/pkguri.cxx) + // treats the whole authority between "://" and the next '/' as the + // nested package url. GetHost() returns only the part after any '@', + // so match the provider and check that substring instead. + OUString sPayloadURL = GetMainURL(INetURLObject::DecodeMechanism::NONE); + sal_Int32 nStart = sPayloadURL.indexOf(u"://"); + if (nStart == -1) { + return false; + } + return isExoticNestedProtocol(sPayloadURL, nStart + 3); } if (isSchemeEqualTo(u"vnd.sun.star.zip")) { @@ -4908,11 +4935,7 @@ bool INetURLObject::IsExoticProtocol() const if (!sPayloadURL.startsWith(u"//")) { return false; } - auto const find = [&sPayloadURL](auto c) { - auto const n = sPayloadURL.indexOf(c, 2); - return n == -1 ? sPayloadURL.getLength() : n; - }; - return INetURLObject(decode(sPayloadURL.subView(2, std::min(find('/'), find('?')) - 2), INetURLObject::DecodeMechanism::WithCharset)).IsExoticProtocol(); + return isExoticNestedProtocol(sPayloadURL, 2); } return false; } -- 2.39.5